嗨嗨!插播了復刻小遊戲後,讓我們繼續回到 Canvas Library 的世界吧,今天要分享的是 Matter.js,也就是之前分享過可以用來操作並模擬物理反應的 js Library。做一個地板,並讓幾顆球落地時彈跳的狀態不一樣就是我們今天的小目標。
一樣先安裝起來~
npm install matter-js
因為此專案是以 React 作為框架,所以不以 getelement 的方式操作 DOM,我們首先要先給主要的 Canvas 元素和包著 Canvas 的 wrapper 作用區域以 useRef()
選起來,幫助我們透過操作 Component 的概念操作 DOM。
因為是以 Typescript 作為開發語言,我在設定 useRef()
時一直報錯,後來是加上 React.MutableRefObject<HTMLDivElement>
以及 React.MutableRefObject<HTMLCanvasElement>
的型別才解決的,想了解為什麼這裡要設定 MutableRefObject
這個型別的可以再深入了解,這裡就不特別說明了,設定完 ref 後把 return 的 JSX 也先寫好,就可以開始設定相關物件參數。
import React, { useEffect, useRef } from 'react';
import Matter from 'matter-js';
const wrapperRef = useRef() as React.MutableRefObject<HTMLDivElement>;
const canvasRef = useRef() as React.MutableRefObject<HTMLCanvasElement>;
return (
<div
ref={wrapperRef}
style={{
width: 300,
height: 300,
}}>
<canvas ref={canvasRef} />
</div>
);
列出來幾個 Main module APIs,也就是我們所有可以調用與設定參數的 API
下方程式碼為例,我們調用了 Engine、Render、World、Bodies 等四個 API,並在 render 中設定一個渲染畫面,裡面包含整個畫面的背景色、使用的 canvas 與 element 。
useEffect(() => {
// module aliases
const Engine = Matter.Engine;
const Render = Matter.Render;
const World = Matter.World;
const Bodies = Matter.Bodies;
// create an engine
const engine = Engine.create();
// create a renderer
const render = Render.create({
element: wrapperRef.current,
engine: engine,
canvas: canvasRef.current,
options: {
width: 300,
height: 300,
background: '#F5F5F5',
wireframes: false,
},
});
...
}, []);
接著我們創造了一個地板,地板的位置以及長寬都是用 rectangle(x 坐標, y 坐標, 長度 , 寬度) 的原理創造出來,只是這裡多了一個沒見過的參數 isStatic
, 這個參數代表固定的,也就是該物件是不會移動的
接著創造了三個圓形,circle (x 坐標, y 坐標, 半徑 ),因為我們希望這個圓有掉下來的效果,因此這邊的 y 坐標都給了 0 ,這樣就會從高處掉落。比較特別的是用到了 restitution
這個參數的意思其實就是掉落或是碰撞後彈跳起來的程度,0 表示發生碰撞後完全不彈跳,1 彈跳的最大程度。
friction
的話則為「阻力」,阻力越大掉落的越緩滿,這裡很特別的是也另外有空氣阻力的參數可以設定,這些參數都可以幫我們模擬更真實世界的環境,大家可以自己調整參數看看效果。
最後,我們只要給 World 世界加上這些 Bodies,並讓引擎與畫面被啟動 run()
即可完成今天的畫面囉!
useEffect(() => {
...
// create three balls and a ground
const floor = Bodies.rectangle(150, 300, 300, 20, {
isStatic: true,
render: {
fillStyle: 'blue',
},
});
const greenBall = Bodies.circle(150, 0, 10, {
restitution: 0.9,
friction: 0.1,
render: {
fillStyle: 'green',
},
});
const redBall = Bodies.circle(150, 0, 10, {
restitution: 0.5,
friction: 0.5,
render: {
fillStyle: 'red',
},
});
const yellowBall = Bodies.circle(100, 0, 10, {
restitution: 0.1,
render: {
fillStyle: 'orange',
},
});
World.add(engine.world, [greenBall, redBall, yellowBall, floor]);
Engine.run(engine);
Render.run(render);
}, []);
以上就是今天的初入 Matter.js,其實他還有很多屬性可以玩,就交給大家去摸索囉!
參考文章:https://blog.arvinh.info/tech/matterjs-intro
程式碼參考:https://paulie.dev/posts/2020/08/react-hooks-and-matter-js/
官方網站 APIs :https://brm.io/matter-js/docs/